package com.onlyxiahui.app.base;

import java.lang.reflect.Constructor;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.onlyxiahui.common.util.OnlyClassUtil;

/**
 * 描述：对象创建工厂
 * date 2016-01-6 7:45:12
 * @author XiaHui
 * @version 0.0.1
 */
public abstract class AbstractFactory extends AbstractComponent {

	protected final Logger logger = LoggerFactory.getLogger(this.getClass());
	private Map<Class<?>, Object> map = new ConcurrentHashMap<Class<?>, Object>();
	private ReentrantLock lock = new ReentrantLock();
	public AbstractFactory(AppContext appContext) {
		super(appContext);
	}

	public <T> void put(Class<T> defineClass, T object) {
		map.put(defineClass, object);
	}

	/**
	 * 根据class获取对象，均为单列(有待验证😂)
	 * 
	 * @author XiaHui
	 * @param classType
	 * @return
	 */
	public <T> T getObject(Class<T> classType) {
		return getObject(classType, false, false);
	}

	/**
	 * 
	 * @author XiaHui
	 * @param classType
	 * @param createNew
	 * @return
	 */
	public <T> T getObject(Class<T> classType, boolean createNew) {
		return getObject(classType, createNew, false);
	}

	/**
	 * 
	 * @author XiaHui
	 * @param classType:被实例化的class对象
	 * @param createNew:true：不管对象是否存在，都新创建对象；false：如果对象已经存在就不新建对象
	 * @param cover:true：如果新建了对象，则覆盖原来的对象。false：不执行覆盖操作
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public <T> T getObject(Class<T> classType, boolean createNew, boolean cover) {
		final ReentrantLock lock = this.lock;
		lock.lock(); // Lock only for visibility, not mutual exclusion
		Object object = null;
		try {
			if (null != classType) {
				boolean has = map.containsKey(classType);
				object = map.get(classType);
				// TODO
				// 不知道同步对象有没有必要写，先注释吧
				if (!has || createNew) {
					object = createObject(classType);
					// 原来对象不存在，或者覆盖，并且新创建的对象不能为空
					if ((!has || cover) && null != object) {
						map.put(classType, object);
					}
				}
			}
		} finally {
			lock.unlock();
		}
		return (T) object;
	}

	/**
	 * 根据class反射创建对象
	 * 
	 * @author XiaHui
	 * @param clazz
	 * @return
	 */
	public Object createObject(Class<?> clazz) {
		Object object = null;

		// 判断是否可以反射实例化，排除接口、抽象类等
		boolean canInstance = OnlyClassUtil.isCanInstance(clazz);

		if (canInstance) {
			Class<?>[] types = { AppContext.class };
			try {
				// 获取一下传入appContext对象的构造函数
				Constructor<?> constructor = clazz.getConstructor(types);
				if (null != constructor) {// 如果存在传染传入appContext对象的构造函数
					Object[] objects = { appContext };
					object = constructor.newInstance(objects);
				}
			} catch (Exception e) {
				logger.error("", e);
			}
			try {
				if (null == object) {
					object = clazz.newInstance();
				}
			} catch (Exception e) {
				logger.error("", e);
			}
			try {
				if (object instanceof Material) {
					((Material) object).setAppContext(appContext);
				}
			} catch (Exception e) {
				logger.error("", e);
			}
		}
		return object;
	}
}
